package com.micro.service.auth.server.config;


import com.micro.service.auth.server.config.handler.LoginFailureHandler;
import com.micro.service.auth.server.config.handler.LoginSuccessHandler;
import com.micro.service.auth.server.config.handler.OauthUserApprovalHandler;
import com.micro.service.auth.server.config.oauth2.CustomClientDetailsService;
import com.micro.service.auth.server.config.oauth2.CustomOAuth2FilterConfig;
import com.micro.service.auth.server.config.properties.SecurityProperties;
import com.micro.service.auth.server.config.security.MyUserDetailsServiceImpl;
import com.micro.service.auth.server.login.sms.SmsCodeAuthenticationSecurityConfig;
import com.micro.service.auth.server.login.validateCode.ValidateCodeFilter;
import com.micro.service.auth.server.login.wechat.WechatAuthenticationSecurityConfig;
import com.micro.service.common.constants.LoginConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.social.security.SpringSocialConfigurer;

/**
 * @author xiucai
 * @description security核心控制类（filter机制）
 * @date 2018/12/25 0025 10:53
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Slf4j
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private RedisConnectionFactory redisConnection;

    @Autowired
    private CustomClientDetailsService clientDetailsService;

    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

    @Autowired
    private WechatAuthenticationSecurityConfig wechatAuthenticationSecurityConfig;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    protected LoginFailureHandler loginFailureHandler;

    @Autowired
    protected LoginSuccessHandler loginSuccessHandler;

    @Bean
    public SessionStrategy sessionStrategy(){return new HttpSessionSessionStrategy();}

    @Bean
    public TokenStore tokenStore() {
        log.info("store-token-redisConnection====================={}",redisConnection);
        return new RedisTokenStore(redisConnection);
    }

    @Autowired
    private CustomOAuth2FilterConfig customOAuth2FilterConfig;

    @Autowired
    private MyUserDetailsServiceImpl userDetailsService;
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        AuthenticationManager manager = super.authenticationManagerBean();
        return manager;
    }

    @Bean
    @Autowired
    public OauthUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
        OauthUserApprovalHandler handler = new OauthUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
        validateCodeFilter.setLoginFailureHandler(loginFailureHandler);
        validateCodeFilter.setSecurityProperties(securityProperties);
        validateCodeFilter.setSessionStrategy(sessionStrategy());

        http
                .apply(customOAuth2FilterConfig)
                .and()
                    .apply(smsCodeAuthenticationSecurityConfig)

                .and()
                    .apply(wechatAuthenticationSecurityConfig)
                .and()
//                    .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)//当有验证码时开启
                    .formLogin()
                    .loginPage(LoginConstant.LOGIN_PAGE)//登录跳转处理对应controller
                    .loginProcessingUrl(LoginConstant.LOGIN_PROCESSING_URL)//登录请求地址
                    .successHandler(loginSuccessHandler)//登录成功处理
                    .failureHandler(loginFailureHandler)//登录失败处理
                .and()
                    .authorizeRequests()
                    .antMatchers(
                            LoginConstant.LOGIN_PAGE,
                            securityProperties.getBrowserProperties().getLoginPage(),
                            LoginConstant.LOGIN_PROCESSING_URL,
                            "/logout",
                            "/wechat/login",
                            "/withdraw",
                            "/sms/**",
                            "/oauth/**",
                            "/oauth/confirm_access",
                            "/css/**","/fonts/**","/images/**","/js/**","/libs/**","/WEB-INF/**","/statics/**"
                    )
                    .permitAll()//不需要登录即可通过的URL
                .and()
                    .authorizeRequests()
                    .anyRequest().authenticated()
                .and()
                    .csrf().disable()
                ;




    }
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/oauth/check_token");
    }



}
